﻿
module HyperF.RemoteExecuter.Functions

open System
open System.IO



let private objSerialize (obj:obj) =
  let formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
  use stream = new System.IO.MemoryStream()
  formatter.Serialize(stream, obj)
  stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
  let data = Array.zeroCreate<byte> (int stream.Length)
  stream.Read(data, 0, (int stream.Length)) |> ignore
  System.Convert.ToBase64String(data)
    


let get_IpAddressByMac (sr:StreamReader) (sw:StreamWriter) =
  let macAddress = sr.ReadLine()
  
  let ret = HyperF.HyperF.get_IpAddressByMac macAddress
  
  sw.WriteLine(true)
  sw.WriteLine(ret.ToString())  



let export_VM (sr:StreamReader) (sw:StreamWriter) =
  let paramVMName = sr.ReadLine()
  let exportDirectory = sr.ReadLine()
  let generateNewID = System.Boolean.Parse(sr.ReadLine())

  HyperF.HyperF.LocalOnly.export_VM paramVMName exportDirectory generateNewID
  sw.WriteLine(true)


let exportEx_VM (sr:StreamReader) (sw:StreamWriter) =
  let paramVMName = sr.ReadLine()
  let exportDirectory = sr.ReadLine()
  let copyVmStorage = System.Boolean.Parse(sr.ReadLine())
  let copyVmRuntimeInformation = System.Boolean.Parse(sr.ReadLine())

  HyperF.HyperF.LocalOnly.exportEx_VM paramVMName exportDirectory copyVmStorage copyVmRuntimeInformation
  sw.WriteLine(true)


let import_VM (sr:StreamReader) (sw:StreamWriter) =
  let importDirectory = sr.ReadLine()
  let generateNewID = Boolean.Parse(sr.ReadLine())

  HyperF.HyperF.LocalOnly.import_VM importDirectory generateNewID
  sw.WriteLine(true)



let importEx_VM (sr:StreamReader) (sw:StreamWriter) =
  let newVmName = sr.ReadLine()
  let generateNewID = Boolean.Parse(sr.ReadLine())
  let importDirectory = sr.ReadLine()
  let createCopy = Boolean.Parse(sr.ReadLine())
  let rootDirectoryToCopy = sr.ReadLine()

  HyperF.HyperF.LocalOnly.importEx_VM newVmName generateNewID importDirectory createCopy rootDirectoryToCopy
  sw.WriteLine(true)


let delete_VM (sr:StreamReader) (sw:StreamWriter) =
  let vmName = sr.ReadLine()
  let deleteVhd = Boolean.Parse( sr.ReadLine() )
  
  let vm = HyperF.HyperF.get_VMByName None vmName
  let arr = HyperF.HyperF.LocalOnly.delete_VM vm deleteVhd
  let ret = objSerialize arr  
  
  sw.WriteLine(true)
  sw.WriteLine(ret)
  


let new_VHD_Differencing (sr:StreamReader) (sw:StreamWriter) =
  let path = sr.ReadLine()
  let parentPath = sr.ReadLine()

  HyperF.HyperF.LocalOnly.new_VHD_Differencing path parentPath
  sw.WriteLine(true)


let new_VHD_Dynamic (sr:StreamReader) (sw:StreamWriter) =
  let path = sr.ReadLine()
  let maxInternalSize = UInt32.Parse(sr.ReadLine())

  HyperF.HyperF.LocalOnly.new_VHD_Dynamic path maxInternalSize
  sw.WriteLine(true)


let new_VHD_Fixed (sr:StreamReader) (sw:StreamWriter) =
  let path = sr.ReadLine()
  let maxInternalSize = UInt32.Parse(sr.ReadLine())

  HyperF.HyperF.LocalOnly.new_VHD_Fixed path maxInternalSize
  sw.WriteLine(true)


let merge_VHD (sr:StreamReader) (sw:StreamWriter) =
  let sourcePath = sr.ReadLine()
  let destinationPath = sr.ReadLine()
  
  HyperF.HyperF.LocalOnly.merge_VHD sourcePath destinationPath
  sw.WriteLine(true)  


let get_VHDInfo (sr:StreamReader) (sw:StreamWriter) =
  let vhdPath = sr.ReadLine()

  let info = HyperF.HyperF.LocalOnly.get_VHDInfo(vhdPath)
  let ret = info.Serialize()

  sw.WriteLine(true)
  sw.WriteLine(ret)


let mount_VHD (sr:StreamReader) (sw:StreamWriter) =
  let vhdPath = sr.ReadLine()
  
  HyperF.HyperF.LocalOnly.mount_VHD vhdPath
  sw.WriteLine(true)

  
let unmount_VHD (sr:StreamReader) (sw:StreamWriter) =
  let vhdPath = sr.ReadLine()
  
  HyperF.HyperF.LocalOnly.unmount_VHD vhdPath
  sw.WriteLine(true)



let new_VM (sr:StreamReader) (sw:StreamWriter) =
  let newName = sr.ReadLine()
  
  let vm = HyperF.HyperF.LocalOnly.new_VM newName
  let ret = vm.Serialize()
  
  sw.WriteLine(true)
  sw.WriteLine(ret)
  

let new_VM_To (sr:StreamReader) (sw:StreamWriter) =
  let newName = sr.ReadLine()
  let path = sr.ReadLine()

  let vm = HyperF.HyperF.LocalOnly.new_VM_To newName path
  let ret = vm.Serialize()
  
  sw.WriteLine(true)
  sw.WriteLine(ret)



let add_VMDVDDiskToController (sr:StreamReader) (sw:StreamWriter) =
  let vmName = sr.ReadLine()
  let controllerName = sr.ReadLine()
  let isoPath = sr.ReadLine()

  let vm = HyperF.HyperF.get_VMByName None vmName
  let diskcontrollers = HyperF.HyperF.get_VMDiskIDEControllers vm
  let controller = diskcontrollers |> Array.find (fun x -> x.Name = controllerName)

  HyperF.HyperF.LocalOnly.add_VMDVDDiskToController controller isoPath
  sw.WriteLine(true)


let add_VMHardDiskToDrive (sr:StreamReader) (sw:StreamWriter) =
  let vmName = sr.ReadLine()
  let controllerName = sr.ReadLine()
  let driveAddress = Int32.Parse( sr.ReadLine() )
  let vhdPath = sr.ReadLine()
  
  let vm = HyperF.HyperF.get_VMByName None vmName
  let controllers = HyperF.HyperF.get_VMDiskControllers vm
  let controller =
    try controllers |> Array.find (fun x -> x.Name = controllerName)
    with _ -> failwithf "Controller not found: %s" controllerName

  let drives = HyperF.HyperF.get_VMDrivesByController controller
  let drive = 
    try drives |> Array.find (fun x -> x.Address = driveAddress)
    with _ -> failwithf "Drive at address %d not found" driveAddress
    
  HyperF.HyperF.LocalOnly.add_VMHardDiskToDrive drive vhdPath
  sw.WriteLine(true)


let add_VMFloppyDisk (sr:StreamReader) (sw:StreamWriter) =
  let vmName = sr.ReadLine()
  let vfdPath = sr.ReadLine()
  
  HyperF.HyperF.LocalOnly.add_VMFloppyDisk vmName vfdPath
  sw.WriteLine(true)
